﻿// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
// This is sample code only, do not use in production environments

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Server;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Client;

namespace Microsoft.ALMRangers.TFSKanbanGuidance.GlobalListUpdater
{
    public class WorkItemChangedEventHandler : ISubscriber
    {
        // ISubscriber - requested event types
        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(WorkItemChangedEvent) };
        }

        // ISubscriber - priority
        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }

        // ISubscriber - name of the plugin
        public string Name
        {
            get { return "Microsoft.ALMRangers.TFSKanbanGuidance.GlobalListUpdater"; }
        }

        // ISubscriber - event handler
        public EventNotificationStatus ProcessEvent(
            TeamFoundationRequestContext requestContext,
            NotificationType notificationType, object notificationEventArgs,
            out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
        {
            string strDump = "";
            statusCode = 0;
            properties = null;
            statusMessage = String.Empty;

            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    // change this object to be a type we can easily get into
                    WorkItemChangedEvent workItemEvent = notificationEventArgs as WorkItemChangedEvent;

                    StringField workItemType = workItemEvent.CoreFields.StringFields.FirstOrDefault(i => i.Name == "System.WorkItemType");
                    if (workItemType != null && workItemType.NewValue == Properties.Settings.Default.ProcessStepWorkItemType)
                    {
                        if (workItemEvent.ChangedFields.StringFields.Any(i => i.ReferenceName == "System.Title"))
                        {
                            var collection = TFSFunctions.GetTeamProjectCollection(requestContext.ServiceHost.VirtualDirectory, workItemEvent.DisplayUrl);
                            var workItemStore = TFSFunctions.GetWorkItemStore(collection);
                            var processSteps = TFSFunctions.ExecuteQuery(workItemStore, Properties.Settings.Default.ProcessStepsQuery, workItemEvent.PortfolioProject, Properties.Settings.Default.ProcessStepWorkItemType);

                            if (processSteps.Count == 0)
                            {
                                strDump = string.Format("Query did not return any results which is expected. Please check the query defined in the settings file.\n\nQuery string was: {0} on Team Project {1}", Properties.Settings.Default.ProcessStepsQuery, workItemEvent.PortfolioProject);
                                WriteInfo(strDump, System.Diagnostics.EventLogEntryType.Warning);
                            }
                            else
                            {
                                bool updateWITD = false;
                                var globalListItems = new List<string>();
                                foreach (WorkItem processStep in processSteps)
                                {
                                    globalListItems.Add(processStep.Title);
                                }

                                var globalListXml = TFSFunctions.ExportGlobalLists(workItemStore);
                                var globalListName = String.Format("{0} - {1}", Properties.Settings.Default.GlobalListPrefix, workItemEvent.PortfolioProject);
                                var newglobalListXml = TFSFunctions.ReplaceGlobalListItems(globalListXml,
                                    globalListName,
                                    globalListItems,
                                    workItemStore.Projects[workItemEvent.PortfolioProject],
                                    workItemStore,
                                    Properties.Settings.Default.GlobalListPrefix,
                                    out updateWITD);
                                TFSFunctions.ImportGlobalList(workItemStore, newglobalListXml);

                                if (updateWITD)
                                {
                                    TFSFunctions.UpdateWITD(workItemStore.Projects[workItemEvent.PortfolioProject],
                                        workItemStore,
                                        Properties.Settings.Default.GlobalListPrefix,
                                        globalListName);

                                    // diagnostics
                                     strDump = string.Format("Updated Work Item Type Definitions in Project {0} to use Global List {1} for allowed values on Kanban State field", workItemEvent.PortfolioProject, globalListName);
                                    WriteInfo(strDump, System.Diagnostics.EventLogEntryType.Information);
                                }
                                // diagnostics
                                strDump = string.Format("Updated Global List {0} with Items {1}", Properties.Settings.Default.GlobalListPrefix, String.Join(",", globalListItems.ToArray()));
                                WriteInfo(strDump, System.Diagnostics.EventLogEntryType.Information);
                            }
                        }
                    }
                }
            }

            catch (Exception ex)
            {
                // diagnostics
                strDump = string.Format("There was a unhandled exception: {0} \n {1}", ex.Message, ex.StackTrace);
                WriteInfo(strDump, System.Diagnostics.EventLogEntryType.Error);
            }

            return EventNotificationStatus.ActionPermitted;
        }

        // helper - dumping diagnostics
        public void WriteInfo(string strDump, System.Diagnostics.EventLogEntryType entryType)
        {

            System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
            log.Source = "TFS Services";
            if (!System.Diagnostics.EventLog.SourceExists(log.Source))
                System.Diagnostics.EventLog.CreateEventSource(log.Source, "Application");

            string strMessage = string.Format(
                "The TFS server plugin {0} provides the following logging information:\n\n{1}",
                System.Reflection.Assembly.GetCallingAssembly().GetName().Name, strDump
                );
            log.WriteEntry(strMessage, entryType);
        }
    }
}